package com.optitronics.service.impl;

import java.io.File;
import java.util.Date;
import java.util.List;

import javax.mail.internet.MimeMessage;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import com.optitronics.beans.EmailMessage;
import com.optitronics.beans.Reseller;
import com.optitronics.beans.ResellerOrder;
import com.optitronics.service.MailSendingService;

/**
 * Mail sending service
 * 
 * @author Bojan Vukotic
 * 
 */
@Service
public class MailSendingServiceImpl implements MailSendingService {

	private Log logger = LogFactory.getLog(this.getClass());

	@Autowired
	private JavaMailSender mailSender;

	@Autowired
	private MessageSource messageSource;

	@Value("${application.url}")
	private String applicationUrl;

	@Value("${mail.from.address}")
	private String fromAddress;

	@Value("${mail.send}")
	private Boolean sendEmail;

	@Value("${mail.send.xls.to}")
	private String sendXLSToEmail;

	/**
	 * Sends registration activation email
	 * 
	 * @param reseller
	 */
	public void sendActivationLink(Reseller reseller) {

		if (Boolean.TRUE.equals(sendEmail)) {

			logger.info("Sending activation link for reseller: email: " + reseller.getEmail() + ", token: "
					+ reseller.getActivationToken());

			String activationLink = applicationUrl + "/resellers/activateRegistration/" + reseller.getEmail() + "/"
					+ reseller.getActivationToken();

			SimpleMailMessage mailMessage = new SimpleMailMessage();

			mailMessage.setFrom(fromAddress);
			String subject = messageSource.getMessage("label.send.actiovation.link.subject", null,
					LocaleContextHolder.getLocale());
			String content = messageSource.getMessage("label.send.actiovation.link.content", null,
					LocaleContextHolder.getLocale());

			content += "\n\n" + activationLink;

			mailMessage.setSubject(subject);
			mailMessage.setTo(reseller.getEmail());
			mailMessage.setText(content);

			try {
				this.mailSender.send(mailMessage);
			} catch (MailException ex) {
				logger.error("E-mail sending failed", ex);
				saveUnsentMessage(mailMessage);
			}
		}
	}

	private void saveUnsentMessage(SimpleMailMessage simpleMailMessage) {
		EmailMessage mailMessage = new EmailMessage();
		mailMessage.setFromAddress(simpleMailMessage.getFrom());

		mailMessage.setSubject(simpleMailMessage.getSubject());
		mailMessage.setToAddress(simpleMailMessage.getTo()[0]);
		mailMessage.setContent(simpleMailMessage.getText());
		mailMessage.setSendingDate(new Date());
		mailMessage.persist();
	}

	private void saveUnsentMessage(MimeMessageHelper helper, String content, List<String> fileNames) {

		EmailMessage mailMessage = new EmailMessage();
		try {
			mailMessage.setFromAddress(helper.getMimeMessage().getFrom()[0].toString());

			mailMessage.setSubject(helper.getMimeMessage().getSubject());
			mailMessage.setToAddress(helper.getMimeMessage().getAllRecipients()[0].toString());
			mailMessage.setContent(content);
			mailMessage.setSendingDate(new Date());

			String fileNamesString = "";
			for (int i = 0; i < fileNames.size(); i++) {
				String prefix = i == 0 ? "" : ",";
				fileNamesString += prefix + fileNames.get(i);
			}

			mailMessage.setAttachmentLocation(fileNamesString);
			mailMessage.persist();

		} catch (Exception ex) {
			logger.error("Error sending unsent message", ex);
		}

	}

	/**
	 * Sends new reseted password
	 * 
	 * @param reseller
	 * @param newPassword
	 */
	public void sendResetPasswordMail(Reseller reseller, String newPassword) {
		if (Boolean.TRUE.equals(sendEmail)) {
			logger.info("Sending reset password mail for reseller: email: " + reseller.getEmail() + ", newPassword: "
					+ newPassword);

			SimpleMailMessage mailMessage = new SimpleMailMessage();
			mailMessage.setFrom(fromAddress);
			String subject = messageSource.getMessage("label.send.password.reset.subject", null,
					LocaleContextHolder.getLocale());

			Object[] params = { newPassword };
			String content = messageSource.getMessage("label.send.password.reset.content", params,
					LocaleContextHolder.getLocale());

			mailMessage.setSubject(subject);
			mailMessage.setTo(reseller.getEmail());
			mailMessage.setText(content);

			try {
				this.mailSender.send(mailMessage);
			} catch (MailException ex) {
				logger.error("E-mail sending failed", ex);
				saveUnsentMessage(mailMessage);
			}
		}
	}

	/**
	 * Sends info that user was registered on Optitronics portal
	 * 
	 * @param reseller
	 */
	public void sendResellerInfoMail(Reseller reseller, String password) {
		if (Boolean.TRUE.equals(sendEmail)) {
			logger.info("Sending info mail for reseller: email: " + reseller.getEmail() + ", password: " + password);

			SimpleMailMessage mailMessage = new SimpleMailMessage();
			mailMessage.setFrom(fromAddress);
			String subject = messageSource.getMessage("label.send.registration.info.subject", null,
					LocaleContextHolder.getLocale());

			Object[] params = { reseller.getEmail(), password, applicationUrl };
			String content = messageSource.getMessage("label.send.registration.info.content", params,
					LocaleContextHolder.getLocale());

			mailMessage.setSubject(subject);
			mailMessage.setTo(reseller.getEmail());
			mailMessage.setText(content);

			try {
				this.mailSender.send(mailMessage);
			} catch (MailException ex) {
				logger.error("E-mail sending failed", ex);
				saveUnsentMessage(mailMessage);
			}
		}
	}

	/**
	 * Resending unsent mail
	 * 
	 * @param unsentMailId
	 */
	public void resendMail(Integer unsentMailId) {
		logger.info("resending email message: " + unsentMailId);
		EmailMessage mailMessage = EmailMessage.findEmailMessages(unsentMailId);
		logger.info("mailMessage: " + mailMessage.getToAddress() + ", subject: " + mailMessage.getSubject());
		try {

			MimeMessage mimeMessage = mailSender.createMimeMessage();
			MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);

			helper.setFrom(mailMessage.getFromAddress());
			helper.setSubject(mailMessage.getSubject());
			helper.setTo(mailMessage.getToAddress());
			helper.setText(mailMessage.getContent());

			if (mailMessage.getAttachmentLocation() != null) {
				String[] fileNames = mailMessage.getAttachmentLocation().split(",");
				for (String fileName : fileNames) {
					File attachmentFile = new File(fileName);
					helper.addAttachment(attachmentFile.getName(), attachmentFile);
				}
			}

			this.mailSender.send(mimeMessage);
			mailMessage.remove();

		} catch (Exception ex) {
			logger.error("E-mail sending failed again", ex);
		}
	}

	/**
	 * Sends zipped xls files for gicen date
	 * 
	 * @param date
	 */
	public void sendXLSMail(ResellerOrder order, List<String> xlsFileNames) {
		if (Boolean.TRUE.equals(sendEmail)) {
			String orderNumber = order.getOrderNumber();
			logger.info("Sending mail with excel files, orderNumber: " + orderNumber);

			MimeMessageHelper helper = null;
			String content = "\n";

			try {

				MimeMessage message = mailSender.createMimeMessage();

				// use the true flag to indicate you need a multipart message
				helper = new MimeMessageHelper(message, true);
				helper.setTo(sendXLSToEmail);
				helper.setFrom(fromAddress);
				helper.setText(content);
				String[] messageParams = { orderNumber, order.getReseller().getName() };
				helper.setSubject(messageSource.getMessage("label.send.xls.files", messageParams,
						LocaleContextHolder.getLocale()));

				for (String xlsFileName : xlsFileNames) {

					File xlsFile = new File(xlsFileName);
					helper.addAttachment(xlsFile.getName(), new FileSystemResource(xlsFile));
				}

				this.mailSender.send(message);

			} catch (Exception ex) {
				logger.error("E-mail sending failed", ex);
				if (helper != null) {
					saveUnsentMessage(helper, content, xlsFileNames);
				}
			}
		}
	}
}
